package com.cdmdotnet.android.teamcity;

import java.io.IOException;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.apache.http.client.ClientProtocolException;
import org.json.JSONException;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

public abstract class AsyncLoader extends Handler {

	public final static String STATUS_KEY = "status";
	public final static String MESSAGE_KEY = "message";
	
	public final static int LOADING_STARTED = 0;
    public final static int LOADING_SUCCEDED = 1;
    public final static int LOADING_FAILED = 2;
	
    private static final LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
    private static final ThreadPoolExecutor threadPool = new ThreadPoolExecutor(3, 3, 10, TimeUnit.SECONDS, queue);;

	public void asyncLoad()
	{
        threadPool.execute(new LoadingTask());
  	}
	
	protected abstract void load() throws ClientProtocolException, IOException, JSONException;
	
	public abstract void onLoadingStarted();
	public abstract void onLoadingFinished(int status, String errMessage);
		
	@Override
	public final void handleMessage (Message msg) {
        switch (msg.getData().getInt(STATUS_KEY)) {
        case LOADING_STARTED:
        	onLoadingStarted();
        	break;
        case LOADING_FAILED:
        	onLoadingFinished(LOADING_FAILED, msg.getData().getString(MESSAGE_KEY));
        	break;
        case LOADING_SUCCEDED:
        	onLoadingFinished(LOADING_SUCCEDED, null);
        	break;
        }
	}
	
	/** Nested class that performs background loading of a data from HTTP*/
    private class LoadingTask implements Runnable {

    	public void run() {
			int status = LOADING_STARTED;
			String errorMessage = null;

			// sending notification back to the main thread: LOADING
			Message msg = obtainMessage();
            Bundle b = new Bundle();
            b.putInt(STATUS_KEY, status);
            msg.setData(b);
            sendMessage(msg);

    		try {
    			load();
    			status = LOADING_SUCCEDED;
			} catch (ClientProtocolException e) {
    			status = LOADING_FAILED;
    			errorMessage = e.getLocalizedMessage();
				e.printStackTrace();
			} catch (IOException e) {
    			status = LOADING_FAILED;
    			errorMessage = e.getLocalizedMessage();
				e.printStackTrace();
			} catch (JSONException e) {
    			status = LOADING_FAILED;
    			errorMessage = e.getLocalizedMessage();
                e.printStackTrace();
			} finally {
    			// sending notification back to the main thread: LOADED/FAILED
    			msg = obtainMessage();
                b = new Bundle();
                b.putInt(STATUS_KEY, status);
                b.putString(MESSAGE_KEY, errorMessage);
                msg.setData(b);
                sendMessage(msg);
			}
        }
    }

}
